#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <errno.h>

// 信号量共用体
union semun {
	int              val;    /* 信号量的值 */
	struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
	unsigned short  *array;  /* Array for GETALL, SETALL */
	struct seminfo  *__buf;  /* Buffer for IPC_INFO
								(Linux-specific) */
}; 

// 将信号量下标为num的信号量做p操作
void sem_p(int semid, int num)
{
	struct sembuf action; // 定义信号量动作结构体变量
	action.sem_num = num; // 信号量下标num
	action.sem_op = -1; // p操作，减一操作
	action.sem_flg = 0; // 默认阻塞状态
	// 对信号量执行p操作
	semop(semid, &action, 1);
}

// 将信号量下标为num的信号量做v操作
void sem_v(int semid, int num)
{
	struct sembuf action; // 定义信号量动作结构体变量
	action.sem_num = num; // 信号量下标num
	action.sem_op = 1; // v操作，加一操作，不需要写+号
	action.sem_flg = 0; // 默认阻塞状态
	// 对信号量执行v操作
	semop(semid, &action, 1);
}

int main(int argc, char const *argv[])
{
	// 1.创建键值
	key_t key = ftok(".", 1);
	if(key == -1)
	{
		perror("ftok failed!\n");
		return -1;
	}
	// 2.创建信号量，获取id号
	int semid = semget(key, 2, IPC_CREAT|IPC_EXCL|0666);
	if(semid == -1)// 创建失败
	{
		if(errno == EEXIST) // 存在而报错
		{
			semid = semget(key, 2, 0666);
			if(semid == -1)
			{
				perror("semget error\n");
				return -1;
			}
		}
	}
	else if(semid > 0) // 创建成功，并且赋值
	{
		// 让信号量下标为0的元素，赋值1
		union semun a; // 定义联合体变量a
		a.val = 1; // 初始值为1
		semctl(semid, 0, SETVAL, a);
		// 让信号量下标为1的元素，赋值0
		a.val = 0; // 初始值为0
		semctl(semid, 1, SETVAL, a);
	}

	while(1)
	{
		printf("p2对信号量arr[1]准备做p操作\n");
		sem_p(semid, 1); // 对下标为0的信号量做p操作
		printf("p2对信号量arr[1]p操作完毕\n\n");

		printf("p2对信号量arr[0]准备做v操作\n");
		sem_v(semid, 0); // 对下标为1的信号量做v操作
		printf("p2对信号量arr[0]v操作完毕\n\n");
	}
	
	return 0;
}
